const wenruns_excel_default_config = {
    rows: 10, // 列
    cols: 10, // 行
    accuracy: 2,
    extra: {},
    grid: {
        width: null,
        height: null,
        borderColor: '#e1e4e9',
        attributes: {},
        cellType: {
            number: [],
            select: [],
            multiSelect: [],
            switch: [],
            radio: [],
            checkbox: [],
        },
    },
    disableSerial: false,
    readonly: false,
    statistic: {
        enable: false, // 启动统计功能
        type: 'both', //
        rows: '*',
        cols: '*',
        values: {
            row: {},
            col: {},
        },
        $rows: {},
        $cols: {},
        area: {
            row: null,
            col: null,
        }
    },
    events: {},
    contextmenu: {
        del_col: 'enabled',
        del_row: 'enabled',
        add_col: 'enabled',
        add_row: 'enabled',
        ins_col: 'enabled',
        ins_row: 'enabled',



        clickEvent: null,
        menus: {}
    }
};
const Selector = function (excel) {
    this.$excel = excel;
    this.init();
}

Selector.prototype = {
    $el: null,
    $empty: null,
    $search: null,
    $loading: null,
    $element: null,
    $optionUl: null,
    selectLis: [],
    asyncLis: [],
    options: {},
    searchStatus: false,
    init() {
        this.selectLis = [];
        this.asyncLis = [];
        this.options = {};
        this.searchStatus = false;
        return this;
    },
    /**
     *
     * @param tagName
     * @returns {HTMLLIElement}
     */
    createEle(tagName) {
        let el = document.createElement(tagName);
        el.setAttribute('wen-select', '');
        return el;
    },
    searchEvent(event) {
        return (e) => {
            var keyword;
            if (event == 'keyup' || event == 'keydown') {
                keyword = e.currentTarget.value;
            } else {
                keyword = e;
            }
            if (event == 'btn' || e.keyCode == 13 || !keyword) {
                if (this.searchStatus && event == 'keyup') {
                    return;
                }
                this.searchStatus = true;
                this.getEmptyEle().remove();
                if (event != 'btn' && e.keyCode == 13) {
                    e.preventDefault();
                    e.stopPropagation();
                }
                this.$excel.checkEvent('select', this.$element.parentElement, keyword, (customEvent,
                    response) => {
                    if (customEvent) {
                        this.selectLis.forEach((el) => {
                            el.remove();
                        });
                        this.asyncLis.forEach((el) => {
                            el.remove();
                        })
                        this.asyncLis = [];
                        if (keyword) {
                            this.getOptionUl().append(this.getLoadingEle());
                            if (response instanceof Promise) {
                                response.then(res => {
                                    this.refreshOptions(res || {}, keyword);
                                })
                            } else {
                                this.refreshOptions(response || {}, keyword)
                            }
                        } else {
                            this.searchStatus = false;
                            this.selectLis.forEach((el) => {
                                this.getOptionUl().append(el);
                            });
                            if (!this.getOptionUl().children.length) {
                                this.getOptionUl().append(this.getEmptyEle())
                            }
                        }
                    } else {
                        this.searchStatus = false;
                        this.selectLis.forEach((li) => {
                            if (!keyword || li.innerText.indexOf(keyword) >= 0) {
                                this.getOptionUl().append(li);
                            } else {
                                li.remove();
                            }
                        });
                        if (!this.getOptionUl().children.length) {
                            this.getOptionUl().append(this.getEmptyEle())
                        }
                    }
                });
            }
        }
    },
    refreshOptions(response, keyword) {
        this.searchStatus = false;
        this.getLoadingEle().remove();
        this.selectLis.forEach((el) => {
            if (el.innerText.indexOf(keyword) >= 0) {
                this.getOptionUl().append(el);
            }
        });
        let asyncOptions = {};
        for (var i in response) {
            if (!Object.keys(this.options).includes(i)) {
                asyncOptions[i] = response[i];
            }
        }
        this.asyncLis = this.asyncLis.concat(this.makeLiOptions(asyncOptions));
        if (!this.getOptionUl().children.length) {
            this.getOptionUl().append(this.getEmptyEle());
        }
        return this;
    },
    /**
     * @returns {HTMLLIElement}
     */
    getSearchEle() {
        if (this.$search) {
            return this.$search;
        }
        this.$search = this.createEle('li');
        this.$search.classList.add('wen-select-search');
        let input = this.createEle('input');
        input.placeholder = '输入关键词搜索';
        input.addEventListener('keyup', this.searchEvent('keyup'))
        input.addEventListener('keydown', this.searchEvent('keydown'));
        let btn = this.createEle('button');
        btn.innerHTML = '搜索';
        btn.type = 'button';
        btn.addEventListener('click', (e) => {
            this.searchEvent('btn').call(this, input.value);
        });
        this.$search.append(input);
        this.$search.append(btn);
        return this.$search;
    },
    /**
     * @returns {HTMLLIElement}
     */
    getEmptyEle() {
        if (this.$empty) {
            return this.$empty;
        }
        this.$empty = this.createEle('li');
        this.$empty.classList.add('empty');
        this.$empty.innerHTML = 'No results found';
        return this.$empty;
    },
    /**
     * @returns {HTMLLIElement}
     */
    getLoadingEle() {
        if (this.$loading) {
            return this.$loading;
        }
        this.$loading = document.createElement('li');
        this.$loading.innerHTML = '加载中';
        return this.$loading;
    },
    /**
     * @returns {HTMLLIElement}
     */
    getOptionUl() {
        if (this.$optionUl) {
            return this.$optionUl;
        }
        this.$optionUl = document.createElement('ul');
        this.$optionUl.classList.add('options-ul');
        return this.$optionUl;
    },
    /**
     * @param options
     * @returns {*[]}
     */
    makeLiOptions(options) {
        let lis = [];
        for (let i in options) {
            let li = this.createEle('li');
            li.classList.add('option-li');
            lis.push(li);
            li.setAttribute('value', i);
            if (i == this.$element.getAttribute("value")) {
                li.setAttribute('selected', '');
            } else {
                li.removeAttribute('selected');
            }
            li.innerHTML = options[i];
            this.getOptionUl().append(li);
            li.addEventListener('click', this.optionEvent(i, options, li));
        }
        return lis;
    },
    optionEvent(i, options, li) {
        return (e) => {
            let val = e.currentTarget.getAttribute('value');
            let old = this.$element.getAttribute('value');
            this.$el.querySelector('li[selected]')?.removeAttribute('selected');
            e.currentTarget.setAttribute('selected', '');
            if (old != val) {
                this.$element.setAttribute('value', val);
                this.$element.innerHTML = options[val];
                if (!this.selectLis.includes(li)) {
                    this.selectLis.push(li);
                    this.options[i] = options[i];
                }
                this.$excel.cellValueChange({
                    newValue: val,
                    oldValue: old,
                    row: this.$element.dataset.row,
                    col: this.$element.dataset.col,
                    ele: this.$element,
                });
                this.$excel.trigger(this.$el.previousElementSibling, 'click');
            }
        }
    },
    setAttributes() {
        this.$excel.setAttributes(...arguments);
        return this;
    },
    show(ele) {
        this.$element = ele;
        if (this.$el) {
            this.$excel.trigger(this.$el.previousElementSibling, 'click');
        }
        let rect = ele.getBoundingClientRect();
        this.$el = this.createEle('ul');
        ele.parentElement.append(this.$el);

        this.$el.classList.add('wen-select');
        this.setAttributes(this.$el, {
            style: {
                'min-width': rect.width + 'px',
                'max-width': (rect.width * 2) + 'px',
                left: rect.left + 'px',
                top: (rect.top + rect.height) + 'px',
            }
        });
        let searchEle = this.getSearchEle();
        searchEle.querySelector('input').value = '';
        this.$el.append(searchEle);

        this.options = this.$excel.getCellOptions(ele.dataset.type, ele.dataset.row, ele.dataset.col);
        // let selectLis = [], asyncLis = [];
        let optionsLi = document.createElement('li');
        this.$el.append(optionsLi);
        let optionUl = this.getOptionUl();
        optionUl.innerHTML = '';
        optionsLi.append(optionUl);
        this.selectLis = this.makeLiOptions(this.options);
        if (this.getOptionUl().children.length) {
            this.getEmptyEle().remove();
        } else {
            this.getOptionUl().append(this.getEmptyEle())
        }
        return this;
    },
    close() {
        this.$el?.remove();
        this.$el = null;
        return this;
    },
}


if (!window.WenRunsExcel) {
    window.WenRunsExcel = function ({
        column,
        $el,
        config = {
            rows: 40,
            cols: 10,
            grid: {
                // width: 150,
                // height: 40,
                attributes: {},

            },
            readonly: false,
        },
        value = [],
    }) {
        window.$wenrunsExcel = this;
        this.$select = new Selector(this);
        this.initAttr();
        this.parametersInit(...arguments);
        return this;
    }
    window.WenRunsExcel.prototype = {
        $el: null,
        $sheet: null,
        $serial: null,
        $input: null,
        $style: null,
        $rows: [],
        $cols: [],
        $observe: null,
        $head: null,

        column: null,
        value: [],
        valueArr: null,
        config: {},
        rowCell: [
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
            'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
        ],
        cells: {},
        boxWidth: 0,
        boxHeight: 0,
        initAttr() {
            this.$el = null;
            this.$sheet = null;
            this.$serial = null;
            this.$input = null;
            this.$style = null;
            this.$rows = [];
            this.$cols = [];
            if (this.$observe) this.$observe.disconnect();
            this.$observe = null;
            this.$head = null;
            this.column = null;
            this.value = [];
            this.valueArr = null;
            this.config = {};
            this.cells = {};
            this.boxWidth = 0;
            this.boxHeight = 0;
            return this;
        },
        // 刷新表格
        refresh(options) {
            this.initAttr();
            if (options === undefined) {
                options = this._options || {};
            }
            return this.parametersInit(options);
        },
        /**
         * 参数解析并初始化
         * @param options
         * @returns {Window.WenRunsExcel}
         */
        parametersInit(options) {
            this._options = options;
            let {
                column,
                $el,
                config,
                value
            } = options;
            this.$el = $el;
            this.column = column;
            this.config = this.assign(wenruns_excel_default_config, config);
            if (value) {
                if (typeof value == 'string') {
                    try {
                        value = JSON.parse(value);
                    } catch (e) {
                        throw new Error('默认值格式不正确!');
                    }
                }
                this.value = value;
                this.toArray();
            }
            this.init();
            return this;
        },
        toArray() {
            if (this.valueArr === null) {
                this.valueArr = Object.values(this.value);
                for (var i in this.valueArr) {
                    this.valueArr[i] = Object.values(this.valueArr[i]);
                }
            }
            return this.valueArr;
        },
        /**
         *
         * @param mutationList
         */
        observeEvent(mutationList) {
            for (let mutation of mutationList) {
                if (!this.config.disableSerial && mutation.target.tagName == 'TR') {
                    let tr = this.$serial.children[mutation.target.dataset.col];
                    if (tr) {
                        tr.style.height = mutation.target.getBoundingClientRect().height + 'px';
                    }
                }
                let classList = Array.from(mutation.target.classList);
                switch (mutation.type) {
                    case 'childList':
                        if (classList.includes('sheet-input') || classList.includes('sheet-select')) {
                            let col = Number(mutation.target.dataset.col),
                                row = Number(mutation.target.dataset.row);
                            if (col > 0 && row > 0) {
                                this.reStatistic(mutation.target)
                            }
                        } else if (classList.includes('wen-sheet')) {
                            this.scrollbar();
                        }
                        break;
                    case 'attributes':
                        if (classList.includes('wen-sheet')) {
                            this.scrollbar();
                        }
                        break;
                    case 'subtree':
                        break;
                    case 'characterData':
                        this.reStatistic(mutation.target)
                        break;
                    default:
                }
            }
            if (this.$el) {
                this.boxHeight = this.$el.offsetHeight;
            }
        },
        /**
         * 初始化
         * @returns {ExcelSheet}
         */
        init() {
            // 挂载节点
            if (typeof this.$el == 'string') {
                this.$el = document.querySelector(this.$el);
            }
            this.$el.innerHTML = '';
            this.$el.classList.add('wen-excel-sheet');
            // 挂载节点宽高
            this.boxWidth = this.$el.offsetWidth;
            this.boxHeight = this.$el.offsetHeight;
            // 监控挂载节点
            this.$observe = new MutationObserver((mutationList) => {
                this.observeEvent.call(this, mutationList);
            });

            // 输入内容
            this.$input = document.createElement('textarea');
            this.setAttributes(this.$input, {
                hidden: true,
                name: this.column ? this.column : '',
                value: JSON.stringify(this.toArray())
            });
            // excel表格挂载工作表
            this.$box = document.createElement('div');
            this.setAttributes(this.$box, {
                'class': ['wen-sheet'],
            });
            this.$observe.observe(this.$box, {
                attributes: true, // 节点属性
                childList: true, // 节点子节点新增或减少
                characterData: true, // 目标节点为characterData节点
                subtree: true, // 子节点的以上属性变化
            });
            // 生成excel表格
            this.makeSheet(this.$box);
            // 挂载excel表内容
            this.$box.append(this.$input);

            this.$el.append(this.$box);
            this.style();
            this.boxHeight = this.$el.offsetHeight;
            this.observeWin();
            this.scrollbar();
            return this;
        },
        /**
         * 窗口大小变化监控
         * @returns {Window.WenRunsExcel}
         */
        observeWin() {
            // window.removeEventListener('resize', this.winResize);
            // window.addEventListener('resize', this.winResize);
            document.body.addEventListener('click', (e) => {
                if (this.$select.$el && !e.target.hasAttribute('wen-select') && !['select', 'multiSelect']
                    .includes(e.target.dataset.type)) {
                    this.trigger(this.$select.$el.previousElementSibling, 'click');
                }
            })
            return this;
        },
        /**
         * 窗口大小变化回调
         * @returns {Window.WenRunsExcel}
         */
        winResize() {
            let me = this.$wenrunsExcel;
            // 当窗口大小改变时，调整页面布局
            me.refresh({
                column: me.column,
                $el: me.$el,
                config: me.config,
                value: me.value,
            });
            return this;
        },
        /**
         * 滚动条高度检查
         * @param box
         */
        scrollbar() {
            if (this.$serialTd && this.$serial) {
                this.$serial.style.height = this.$sheet.getBoundingClientRect().height + 'px';
                this.$serialTd.width = this.$serial.getBoundingClientRect().width;
            }
        },
        /**
         * 是否未统计列
         * @param row
         * @param config
         * @returns {boolean}
         */
        isRowStatistic(row, config = null) {
            var statistic = config || this.getConfig('statistic');
            if (statistic.type == 'both' || statistic.type == 'row') {
                if (statistic.rows == '*' || statistic.rows.includes(this.cells[row - 1])) {
                    return true;
                }
            }
            return false;
        },
        /**
         * 是否未统计行
         * @param col
         * @param config
         * @returns {boolean}
         */
        isColStatistic(col, config = null) {
            var statistic = config || this.getConfig('statistic');
            if (statistic.type == 'both' || statistic.type == 'col') {
                if (statistic.cols == '*' || statistic.cols.includes(col)) {
                    return true;
                }
            }
            return false;
        },
        /**
         * 重新统计
         * @param el
         */
        reStatistic(el) {
            var row = Number(el.dataset.row),
                col = Number(el.dataset.col),
                values = this.toArray(),
                statistic = this.getConfig('statistic');
            if (isNaN(row) || isNaN(col)) {
                this.$input.value = JSON.stringify(values);
            } else {
                var isRow = this.isRowStatistic(row, statistic);
                var isCol = this.isColStatistic(col, statistic);
                if (statistic.enable && (isRow || isCol)) {
                    var newVal, oldVal = Number(el.placeholder);
                    switch (el.tagName) {
                        case 'SPAN':
                            newVal = Number(el.innerText);
                            break;
                        default:
                            newVal = Number(el.value);
                    }
                    if (isNaN(newVal)) newVal = 0;
                    if (isNaN(oldVal)) oldVal = 0;
                    var diffVal = newVal - oldVal;
                    el.placeholder = newVal;
                    switch (el.dataset.type) {
                        case 'select':
                            newVal = el.getAttribute('value');
                            break;
                        default:
                    }
                    if (statistic.area.row == row || statistic.area.col == col) { // 统计行 或 列，其初始值为0
                        oldVal = 0;
                        diffVal = newVal;
                    }
                    if (isRow) {
                        if (statistic.values.row[row]) {
                            statistic.values.row[row] += diffVal;
                        } else {
                            statistic.values.row[row] = diffVal;
                        }
                    }
                    if (isCol) {
                        if (statistic.values.col[col]) {
                            statistic.values.col[col] += diffVal;
                        } else {
                            statistic.values.col[col] = diffVal;
                        }
                    }
                    if (!values[col - 1]) {
                        values[col - 1] = [];
                    }
                    values[col - 1][row - 1] = newVal;
                    this.$input.value = JSON.stringify(values);
                    return this.renderStatistic();
                } else {
                    this.$input.value = JSON.stringify(values);
                }
            }
            return this;
        },
        /**
         * 模拟事件触发
         * @param ele
         * @param event
         */
        trigger(ele, event) {
            if (ele) {
                var $event = document.createEvent("HTMLEvents");
                $event.initEvent(event, true, true);
                if (typeof ele == 'string') {
                    ele = document.querySelector(ele);
                }
                ele.dispatchEvent($event);
            }
            return this;
        },
        /**
         * 解释复制内容
         * @param content
         * @param row
         * @param col
         */
        parsePasteContent({
            content,
            row,
            col
        }) {
            if (!content) {
                return;
            }
            row = Number(row);
            col = Number(col);
            content = content.split(/\r\n|\r|\n/);
            content.forEach((colContent, i) => {
                if (colContent && this.$cols[col + i]) {
                    colContent = colContent.split(/\s+|\t+/img);
                    colContent.forEach((value, j) => {
                        let rows = this.$cols[col + i];
                        if (rows) {
                            let td = rows[row + j];
                            if (td) {
                                let inputEle = td.querySelector('input.sheet-input');
                                if (inputEle) {
                                    inputEle.value = value;
                                    this.trigger(inputEle, 'change');
                                }
                            }
                        }
                    })
                }
            })
        },
        /**
         * 自定义粘贴
         * @param row
         * @param col
         */
        customPaste({
            row,
            col
        }) {
            let tipEle = document.createElement('div');
            tipEle.style = `
                        position: fixed;
                        z-index: 9999999999999;
                        top: 0px;
                        left: 0px;
                        width: 100vw;
                        height: 100vh;
                        display: flex;
                        justify-content: center;
                        align-items: center;
                        background: rgba(0, 0, 0, 0.2);
                `;
            tipEle.innerHTML = `
                    <div style=" width: 500px;max-width: 90%;background: white;padding: 10px;box-shadow: 0px 0px 15px darkgrey;border-radius: 3px;">
                        <div style="text-align: center;"><strong>温馨提示</strong></div>
                        <div>
                            <div style="color: gray;font-size: .4rem;">由于您的浏览器不支持粘贴板，请将内容复制到一下输入框后点击”确定“即可。</div>
                            <div>
                                <textarea class="clipboard-content" style="width:100%;height: 100px;resize: none;outline: none;padding:5px;"></textarea>
                            </div>
                        </div>
                        <div style="text-align: center;">
                            <input class="paste-btn-confirm" type="button" value="确定" alt="确定粘贴" style="padding:5px 10px; color:white;border-radius: 3px ; -webkit-box-shadow: none; box-shadow: none; border: 1px solid transparent;background-color: #00c0ef;border-color: #00acd6;-webkit-appearance: button;cursor: pointer;" />
                       </div>
                    </div>
                `;
            window.parent.document.body.append(tipEle);
            tipEle.querySelector('.clipboard-content').focus();
            tipEle.querySelector('.paste-btn-confirm').addEventListener('click', (e) => {
                let content = tipEle.querySelector('.clipboard-content').value;
                tipEle.remove();
                this.parsePasteContent({
                    content,
                    col,
                    row,
                })
            })
        },
        checkEvent(eveType, td, argv, fn) {
            let row = this.cells[Number(td.dataset.row) - 1],
                col = Number(td.dataset.col),
                events = this.getConfig('events', {}),
                eventFn = events[row + col + '@' + eveType] || events[row + '@' + eveType] || events[col + '@' +
                    eveType],
                response = null;

            if (eventFn) {
                if (typeof eventFn == 'string') {
                    eval(`eventFn = ${eventFn}`);
                }
                response = eventFn.call(this, td, argv);
            }
            if (fn) {
                fn.call(this, eventFn ? true : false, response);
            }
            return this;
        },
        /**
         * 注册事件
         * @param ele
         * @param type
         * @returns {Window.ExcelSheet}
         */
        registerEvents(ele, type) {
            switch (type) {
                case 'grid.td':
                    this.cellEvent(ele);
                    break;
                case 'rightMount':
                    ele.addEventListener('contextmenu', (event) => {
                        this.contextmenu(event);
                    });
                    break;
                default:
            }
            return this;
        },
        contextmenu(event) {
            event.preventDefault();
            if (!this.$contextmenu) {
                // 监听document上的点击，用于关闭自定义菜单
                document.addEventListener('click', (e) => {
                    if (this.$contextmenu) {
                        this.$contextmenu.remove();
                    }
                    if (this.$contextmenuTarget) {
                        this.$contextmenuTarget.classList.remove('wen-context-target');
                        this.$contextmenuTarget = null;
                    }
                });
            }
            if (this.$contextmenuTarget) {
                this.$contextmenu.remove();
                this.$contextmenuTarget.classList.remove('wen-context-target');
                this.$contextmenuTarget = null;
            }
            let element = event.target;
            while (element.tagName != "TD") {
                element = element.parentElement;
            }
            element.classList.add('wen-context-target')
            this.$contextmenuTarget = element;
            const row = Number(this.$contextmenuTarget.dataset.row),
                col = Number(this.$contextmenuTarget.dataset.col);
            const actions = Object.assign({
                del_row: '删除列',
                del_col: '删除行',
                add_row: '添加列',
                add_col: '添加行',
                ins_row: '插入列',
                ins_col: '插入行',
            }, this.config.contextmenu.menus || {});
            this.$contextmenu = document.createElement('div');
            this.$contextmenu.classList.add('wen-excel-context-menu');
            for (let i in actions) {
                let el = document.createElement('div');
                el.innerHTML = actions[i];
                el.setAttribute('wen-excel-context-item', '');
                el.dataset.action = i;
                this.$contextmenu.append(el);
                if ((row <= 0 && (i == 'del_row' || i == 'ins_row')) || (col <= 0 && (i == 'del_col' || i == 'ins_col')) || this.disableContextmenu(i, row, col)) {
                    el.setAttribute('disabled', "");
                } else {
                    el.setAttribute('enabled', "");
                }
            }
            // 处理自定义菜单按钮的点击事件
            this.$contextmenu.addEventListener('click', (subEvent) => {
                if (subEvent.target.hasAttribute('wen-excel-context-item')) {
                    if (subEvent.target.hasAttribute('disabled')) {
                        return;
                    }
                    let fn = this.config.contextmenu.clickEvent;
                    if (typeof fn == 'string') {
                        eval('fn =' + fn);
                    }
                    if (typeof fn == 'function') {
                        let rsp = fn.call(this, {
                            col,
                            row,
                            event: subEvent,
                            action: subEvent.target.dataset.action,
                            callback: () => {
                                this.contextmenuClick(subEvent, col, row);
                            }
                        });
                        if (rsp instanceof Promise) {
                            rsp.then(() => {
                                this.contextmenuClick(subEvent, col, row);
                            });
                        } else if (rsp !== false) {
                            this.contextmenuClick(subEvent, col, row);
                        }
                    } else {
                        this.contextmenuClick(subEvent, col, row);
                    }

                }
            });
            let x = event.pageX || event.clientX;
            let y = event.pageY || event.clientY;

            this.$contextmenu.style.left = `${x}px`;
            this.$contextmenu.style.top = `${y}px`;
            // 将自定义菜单添加到文档中
            document.body.appendChild(this.$contextmenu);
            const rect = this.$contextmenu.getBoundingClientRect();
            if (rect.right > window.innerWidth) {
                let right = rect.right - window.innerWidth;
                this.$contextmenu.style.left = `${x - right}px`
            }
            if (rect.bottom > window.innerHeight) {
                let bottom = rect.bottom - window.innerHeight;
                this.$contextmenu.style.top = `${y - bottom}px`;
            }
            return this;
        },

        contextmenuClick(subEvent, col, row) {
            switch (subEvent.target.dataset.action) {
                case 'del_col':
                    if (col > 0) {
                        this.deleteCells('col', col - 1);
                    }
                    break;
                case 'del_row':
                    if (row > 0) {
                        this.deleteCells('row', row - 1);
                    }
                    break;
                default:
            }
            return this;
        },

        disableContextmenu(action, row, col) {
            let cellValue = this.getCellValue(row - 1);
            let value = this.config.contextmenu[action];
            if (typeof value == 'object') {
                return Object.values(value).filter((v) => {
                    return v == col || v == cellValue || v == cellValue + col;
                }).length > 0;
            }
            return value == 'disabled'
        },
        deleteCells(cellType, cellIndex) {
            let statistic = this.getConfig('statistic', {});
            if (cellType == 'col') {
                if (this.valueArr[cellIndex]) {
                    this.valueArr.splice(cellIndex, 1);
                    this.$input.value = JSON.stringify(this.valueArr);
                }
                const colElement = this.$cols.splice(cellIndex + 1, 1).pop();
                colElement[0].parentElement.remove();
                Array.from(this.$sheet.children).forEach((tr, i) => {
                    tr.dataset.col = i;
                    const childList = tr.querySelectorAll('[data-col]');
                    childList.forEach((el) => {
                        el.dataset.col = i;
                    });
                });
                this.$serial.children[cellIndex + 1].remove();
                this.$rows.forEach((elements, i) => {
                    elements.splice(cellIndex + 1, 1).pop();
                    if (i === 0 && this.$serial) {
                        elements.forEach((td, j) => {
                            if (j > 0) {
                                td.querySelector('.serial-value').innerHTML = j;
                                if (this.$serial.children[j]) {
                                    this.$serial.children[j].querySelector('.serial-value').innerHTML = j;
                                    this.$serial.children[j].dataset.col = j;
                                    this.$serial.children[j].querySelectorAll('[data-col]')?.forEach((el) => {
                                        el.dataset.col = j;
                                    });
                                }
                            }
                        });
                    }
                });
                this.config.cols--;
                if (statistic.values.col && statistic.values.col[cellIndex + 1]) {
                    delete statistic.values.col[cellIndex + 1];
                }
                if (statistic.values.row) {
                    let row = {};
                    for (let i in statistic.values.row) {
                        if (!row[i]) {
                            row[i] = 0;
                        }
                        this.valueArr.forEach((item) => {
                            let v = Number(item[i - 1]);
                            if (isNaN(v)) {
                                return;
                            }
                            row[i] += v;
                        });
                    }
                    statistic.values.row = row;
                }

            } else {
                let cols = {}, rows = {};
                this.valueArr.forEach((item, n) => {
                    item.splice(cellIndex, 1);
                    if (statistic.values.col[n + 1] !== undefined) {
                        cols[n + 1] = 0;
                        item.forEach((v) => {
                            v = Number(v);
                            if (isNaN(v)) {
                                return;
                            }
                            cols[n + 1] += v;
                        });
                    }
                });
                if (statistic.values.row) {
                    delete statistic.values.row[cellIndex + 1];
                    for (let i in statistic.values.row) {
                        if (i > cellIndex) {
                            rows[i - 1] = statistic.values.row[i];
                        } else {
                            rows[i] = statistic.values.row[i];
                        }
                    }

                }
                statistic.values.col = cols;
                statistic.values.row = rows;


                this.$input.value = JSON.stringify(this.valueArr);
                if (this.$rows[cellIndex + 1]) {
                    let tds = this.$rows.splice(cellIndex + 1, 1).pop();
                    tds.forEach((td) => {
                        td.remove();
                    });
                }
                this.$cols.forEach((tds, i) => {
                    tds.splice(cellIndex + 1, 1);
                    tds.forEach((td, j) => {
                        if (j < cellIndex) {
                            return;
                        }
                        td.dataset.row = j;
                        td.querySelectorAll('[data-row]').forEach((el) => {
                            el.dataset.row = j;
                        });
                        if (i === 0) {
                            td.innerHTML = this.getCellValue(j - 1);
                        }
                    });
                });

            }

            if (this.$serial) {
                this.$serial.style.height = this.$sheet.getBoundingClientRect().height + 'px';
                this.$serial.style.width = this.$rows[0][0].getBoundingClientRect().width + 'px';
            }

            this.renderStatistic();
            return this;

        },

        // 单元格事件
        cellEvent(ele) {
            // input输入框
            let inputEle = ele.querySelector("input.sheet-input");
            if (inputEle) {
                inputEle.addEventListener('focus', (e) => {
                    inputEle.placeholder = inputEle.value;
                    inputEle.value = '';
                    this.checkEvent('focus', inputEle.parentElement);
                });
                inputEle.addEventListener('blur', (e) => {
                    if (!inputEle.value) {
                        inputEle.value = inputEle.placeholder
                    }
                    this.checkIfAddCol(e.currentTarget);
                    this.checkEvent('blur', inputEle.parentElement);
                });
                inputEle.addEventListener('change', (e) => {
                    this.cellValueChange({
                        newValue: e.target.value,
                        oldValue: e.target.placeholder,
                        row: e.target.dataset.row,
                        col: e.target.dataset.col,
                        ele: e.target,
                    });
                });
                // 粘贴功能
                inputEle.addEventListener('paste', (e) => {
                    this.pasteEvent(e);
                })
            }
            // select选择框
            let inputSelect = ele.querySelector("div.sheet-select");
            if (inputSelect) {
                inputSelect.addEventListener('click', (e) => {
                    if (e.currentTarget.hasAttribute('select')) {
                        e.currentTarget.removeAttribute('select');
                        this.$select.close();
                    } else {
                        e.currentTarget.setAttribute('select', '')
                        this.showSelectOptions(e.currentTarget)
                    }

                })
            }

            return this;
        },
        // 粘贴事件
        pasteEvent(event) {
            event.preventDefault();
            event.stopPropagation();
            this.checkEvent('paste', event.currentTarget.parentElement, null, (customEvent) => {
                if (!customEvent) {
                    var col = event.currentTarget.dataset.col,
                        row = event.currentTarget.dataset.row;
                    if (!(event.clipboardData && event.clipboardData.items)) {
                        this.customPaste({
                            col: col,
                            row: row,
                        })
                        return;
                    }
                    let items = event.clipboardData.items;
                    try {
                        for (var i in items) {
                            var vo = items[i];
                            switch (vo.kind) {
                                case 'string':
                                    vo.getAsString((content) => {
                                        if (content) {
                                            if (!(/(<.*?>.*<\/.*?>)|(\{.*;.*\})/img.test(content))) {
                                                this.parsePasteContent({
                                                    content: content,
                                                    col,
                                                    row,
                                                })
                                            }
                                        }
                                    });
                                    break;
                                default:
                            }
                        }
                    } catch (err) {
                        swal.fire({
                            title: '错误提示',
                            html: '数据解析失败：' + err.message,
                        });
                    }
                }
            });

            return this;
        },


        /**
         * 判断是否自动追加行
         * @param col
         * @param row
         */
        checkIfAddCol(el) {
            if (this.config.statistic.enable && el.value) {
                let col = Number(el.dataset.col),
                    row = Number(el.dataset.row);
                if (col > this.config.cols) {
                    this.addCol(col + 1, this.config.rows);
                    this.renderStatistic();
                }
            }
            return this;
        },
        /**
         *
         * @param ele
         * @returns {Window.WenRunsExcel}
         */
        showSelectOptions(ele) {
            this.$select.show(ele);
            return this;
        },
        /**
         * 表格值变化
         * @param newValue
         * @param oldValue
         * @param row
         * @param col
         * @param ele
         * @param event
         * @returns {Window.WenRunsExcel}
         */
        cellValueChange({
            newValue,
            oldValue,
            row,
            col,
            ele,
            event = true
        }) {
            let td = ele.parentElement;
            // todo:: change事件触发
            row = Number(row);
            col = Number(col);
            let statistic = this.getConfig('statistic', {});
            let values = this.toArray(),
                rowIndex = row - 1,
                colIndex = col - 1,
                i = 0,
                rows = this.getConfig('rows', 0);
            while (colIndex - i > 0) {
                if (!values[colIndex - i]) {
                    values[colIndex - i] = [];
                }
                for (var j = 0; j < rows; j++) {
                    if (i == 0 && j == rowIndex) {
                        values[colIndex - i][j] = newValue;
                    } else if (values[colIndex - i][j] === undefined) {
                        values[colIndex - i][j] = '';
                        this.checkStatistic({
                            config: statistic,
                            col: colIndex - i + 1,
                            row: j + 1,
                            value: '',
                        })
                        this.resetCellValue({
                            td: this.$cols[colIndex - i + 1][j + 1],
                            value: values[colIndex - i][j],
                            row: j + 1,
                            col: colIndex - i + 1
                        });
                    }
                }
                i++;
            }
            this.resetCellValue({
                td,
                value: newValue,
                row: row,
                col: col,
            });
            this.reStatistic(ele);
            event && this.checkEvent('change', td);
            return this;
        },
        setCellValue(td, value, event = true) {
            let row = Number(td.dataset.row),
                col = Number(td.dataset.col),
                // values = this.toArray(),
                oldVal = '';
            let el = td.querySelector('.sheet-value');
            if (el) {
                oldVal = el.innerHTML;
                el.placeholder = oldVal;
            } else if (el = td.querySelector('.sheet-select')) {
                oldVal = el.getAttribute('value');
            } else if (el = td.querySelector('.sheet-input')) {
                oldVal = el.value;
            }
            this.cellValueChange({
                newValue: value,
                oldValue: oldVal,
                row,
                col,
                ele: el,
                event,
            });
            return this;
        },
        resetCellValue({
            td,
            value,
            row,
            col
        }) {
            if (td) {
                let type = this.getCellType(row, col),
                    ele = null,
                    originValue = value;
                switch (type) {
                    case 'select':
                        let options = this.getCellOptions('select', row, col);
                        value = options[value] || value;
                        ele = td.querySelector('div.sheet-select');
                        if (ele) {
                            ele.setAttribute('value', originValue);
                            ele.innerHTML = value;
                        }
                        break;
                    case 'number':
                        if (value) {
                            let accuracy = Math.pow(10, this.getAccuracy());
                            value = Math.round(Number(value) * accuracy) / accuracy;
                        }
                    default:
                        ele = td.querySelector('input.sheet-input');
                        if (ele) {
                            // ele.placeholder = value;
                            ele.value = value;
                        }
                }
                if (!ele) {
                    ele = td.querySelector('span.sheet-value');
                    if (ele) {
                        ele.innerHTML = value;
                    }
                }
            }
            return this;
        },
        /**
         * 获取值
         * @param col
         * @param row
         * @returns {string|*|string|ExcelSheet.valueArr}
         */
        getValue(col, row) {
            if (this.valueArr) {
                let values = this.toArray();
                if (typeof col == 'undefined' && typeof row == 'undefined') {
                    return values;
                }
                let colValues = values[col];
                if (typeof row == 'undefined') {
                    return colValues;
                }
                if (typeof colValues == 'undefined' || typeof colValues[row] == 'undefined') {
                    return '';
                }
                return colValues[row];
            }
            return '';
        },
        /**
         * 生成excelSheet表
         * @returns {ExcelSheet}
         */
        makeSheet() {
            this.$sheet = document.createElement('table');
            if (!this.disableSerial) {
                this.$serial = document.createElement('table');
                this.$el.append(this.$serial);
            }
            this.$box.append(this.$sheet);
            this.setAttributes(this.$serial, {
                'class': ['sheet-table', 'sheet-serial-table'],
            });
            let gridWidth = this.getConfig('grid.width', 0);
            if (gridWidth) {
                this.$sheet.style['table-layout'] = 'fixed';
            }
            this.setAttributes(this.$sheet, {
                'class': ['sheet-table'],
            });

            this.makeHead();
            this.makeGrid();
            this.makeFooter();
            this.registerEvents(this.$sheet, 'rightMount');
            this.registerEvents(this.$serial, 'rightMount');
            return this;
        },
        /**
         * 判断是否只读
         * @param col
         * @param row
         * @returns {boolean}
         */
        isReadonly(col, row) {
            let readonly = this.getConfig('readonly');
            if (typeof readonly == 'boolean') {
                return readonly;
            }
            return readonly && (readonly.includes(col) || readonly.includes(this.cells[row - 1]) || readonly
                .includes(this.cells[row - 1] + col));
        },
        /**
         * 判断是否可以编辑
         * @param col
         * @param row
         * @returns {string}
         */
        editable(col, row) {
            if (this.isReadonly(col, row)) {
                return false;
            }
            return true;
        },
        /**
         * 生成excel格子
         * @returns {ExcelSheet}
         */
        makeGrid() {
            let cols = this.getConfig('cols'), // 行数
                rows = this.getConfig('rows'),
                lenCols = this.getValue().length,
                // lenRows = this.getValue(0).length,
                statistic = this.getConfig('statistic'); // 列数
            if (cols < lenCols) {
                cols = lenCols; // 默认值的行数
            }
            // if (rows < lenRows) {
            //     rows = lenRows;
            // }
            if (statistic.enable) {
                switch (statistic.type) {
                    case 'both':
                        cols += 1;
                        rows += 1;
                        break;
                    case 'col':
                        rows += 1;
                        break;
                    case 'row':
                    default:
                        cols += 1;
                }
            }
            for (var i = 0; i < cols; i++) {
                this.appendCol(i + 1, rows)
            }
            return this.renderStatistic();
        },
        /**
         * 追加行
         * @param col
         * @param rows
         * @returns {HTMLTableRowElement}
         */
        appendCol(col, rows) {
            let statistic = this.getConfig('statistic');
            this.$cols[col] = [];
            // 创建行
            let tr = document.createElement('tr');
            this.setAttributes(tr, {
                'class': ['sheet-col'],
                'data-col': col,
            })
            this.$sheet.append(tr);
            if (!this.config.disableSerial) {
                // 生成序号元素
                let serialTd = this.makeSerial(tr, 'sheet-row', col, col);
                this.$cols[col][0] = this.$rows[0][col] = serialTd;
            }

            // 创建列
            for (var j = 0; j < rows; j++) {
                let td = document.createElement('td');
                this.setAttributes(td, {
                    'class': ['sheet-row', 'sheet-row-' + this.getCellType(j + 1, col)],
                    'data-col': col,
                    'data-row': j + 1,
                });
                let value = this.getValue(col - 1, j);
                td.innerHTML = this.makeValue({
                    value,
                    col: col,
                    row: j + 1
                });
                tr.append(td);
                this.registerEvents(td, 'grid.td');
                this.$cols[col][j + 1] = this.$rows[j + 1][col] = td;
                this.checkStatistic({
                    config: statistic,
                    col: col,
                    row: j + 1,
                    value: value,
                })
            }
            if (this.config.cols < col) {
                this.config.cols = col;
            }
            if (this.config.rows < rows) {
                this.config.rows = rows;
            }
            return tr;
        },
        /**
         * 渲染统计数据
         * @returns {Window.WenRunsExcel}
         */
        renderStatistic() {
            let statistic = this.getConfig('statistic', {}),
                cols = this.getValue().length,
                rows = this.getConfig('rows', 0);
            if (!statistic.enable) {
                return this;
            }
            let accuracy = Math.pow(10, this.getAccuracy());
            if (statistic.type == 'both' || statistic.type == 'col') {
                rows++;
                let rowsEle = this.$rows[rows];
                if (Object.values(statistic.values.col).filter((val) => {
                    return val != 0
                }).length) {
                    for (let col in statistic.values.col) {
                        let el = rowsEle[col].querySelector('input.sheet-input');
                        let value = statistic.values.col[col];
                        if (value) {
                            value = Math.round(Number(value) * accuracy) / accuracy;
                        }
                        if (el) {
                            el.value = value;
                        } else if (el = rowsEle[col].querySelector('.sheet-value')) {
                            el.innerHTML = value;
                        }
                        statistic.$cols[col] = rowsEle[col];
                    }
                }
                statistic.area.row = rows;
            }
            if (statistic.type == 'both' || statistic.type == 'row') {
                cols++;
                let colsEle = this.$cols[cols];
                if (!colsEle) {
                    this.addCol(cols, rows);
                    colsEle = this.$cols[cols];
                }
                if (Object.values(statistic.values.row).filter((val) => {
                    return val != 0
                }).length) {
                    for (let row in statistic.values.row) {
                        let rowEle = colsEle[row];
                        let value = statistic.values.row[row];
                        if (value) {
                            value = Math.round(Number(value) * accuracy) / accuracy;
                        }
                        let el = rowEle.querySelector('input.sheet-input');
                        if (el) {
                            el.value = value;
                        } else if (el = rowEle.querySelector('.sheet-value')) {
                            el.innerHTML = value;
                        }
                        statistic.$rows[row] = colsEle[row];
                    }
                }
                statistic.area.col = cols;
            }
            return this;
        },
        /**
         * 新增行
         * @param col
         * @param rows
         * @returns {Window.WenRunsExcel}
         */
        addCol(col, rows) {
            this.config.cols++;
            let tr = this.appendCol(col, rows);
            return this;
        },
        getAccuracy() {
            return this.config.accuracy || 2;
        },
        getAttributes(row, col) {
            let rowCell = this.cells[row - 1];
            let attributes = this.getConfig('grid.attributes', {});
            let colAttributes = attributes[col] || {};
            let rowAttributes = attributes[rowCell] || {};
            let combineAttributes = attributes[rowCell + col] || {};
            for (let i in attributes) {
                let reg1 = new RegExp(`(^|,)${rowCell}(,|$)`);
                if (i != rowCell && reg1.test(i)) {
                    rowAttributes = this.assign(attributes[i], rowAttributes);
                }
                let reg2 = new RegExp(`(^|,)${col}(,|$)`);
                if (i != col && reg2.test(i)) {
                    colAttributes = this.assign(attributes[i], colAttributes);
                }
                let reg3 = new RegExp(`(^|,)${rowCell}${col}(,|$)`);
                if (i != (rowCell + col) && reg3.test(i)) {
                    combineAttributes = this.assign(attributes[i], combineAttributes);
                }
            }
            return this.assign(colAttributes, rowAttributes, combineAttributes);
        },
        assign(obj1, obj2) {
            let obj = {};
            Array.from(arguments).forEach((item) => {
                for (let i in item) {
                    if (!item[i] || item[i] instanceof Array || item[i] instanceof Function || typeof item[
                        i] != 'object') {
                        obj[i] = item[i];
                    } else {
                        obj[i] = this.assign(obj[i] || {}, item[i]);
                    }
                }
            })
            return obj;
        },
        attrToString(attributes) {
            if (attributes && typeof attributes == 'object') {
                let str = '';
                for (let i in attributes) {
                    let value = attributes[i];
                    if (value && typeof value == 'object') {
                        if (i == 'style') {
                            let style = '';
                            Object.keys(value).forEach((name) => {
                                style += `${name}:${value[name]};`;
                            })
                            value = style;
                        } else {
                            value = JSON.stringify(value);
                        }
                    }
                    str += ` ${i}="${value}" `;
                }
                return str;
            }
            return attributes || '';
        },
        /**
         * 生成编辑输入框
         * @param value
         * @param row 列
         * @param col 行
         * @returns {string}
         */
        makeValue({
            value,
            row,
            col
        }) {
            if (!value) {
                value = '';
            }
            let accuracy = Math.pow(10, this.getAccuracy());
            let step = 1 / accuracy;
            let type = this.getCellType(row, col);
            let attributes = this.attrToString(this.getAttributes(row, col));
            if (this.editable(col, row)) {
                switch (type) {
                    case 'select':
                        let originValue = value;
                        if (value) {
                            let options = this.getCellOptions('select', row, col);
                            value = options[value] || value;
                        }
                        return `<div class="sheet-select" data-row="${row}" data-col="${col}"  value="${originValue}" placeholder="请选择" data-type="select" ${attributes}>${value}</div>`;
                    case 'number':
                        if (value) {
                            value = Math.round(Number(value) * accuracy) / accuracy;
                        }
                        break;
                    default:
                }
                return `<input class="sheet-input" type="${type}" data-row="${row}" data-col="${col}" value="${value}" placeholder="${value}" step="${step}" ${attributes} />`;
            } else {
                switch (type) {
                    case 'select':
                        let options = this.getCellOptions('select', row, col);
                        value = options[value] || value;
                        break;
                    default:
                }
                return `<span class="sheet-value" placeholder="${value}" ${attributes} data-row="${row}" data-col="${col}">${value}</span>`;
            }
        },
        /**
         * 获取选项配置
         * @param type
         * @param row
         * @param col
         * @returns {*}
         */
        getCellOptions(type, row, col) {
            let options = this.getConfig('grid.cellType.' + type, {});
            let cellRow = this.cells[row - 1];
            return options[cellRow + col] || options[cellRow] || options[col] || {};
        },
        /**
         * @param row 列
         * @param col 行
         */
        getCellType(row, col) {
            let types = this.getConfig('grid.cellType', {});
            let type = 'text';
            let rowCell = this.cells[row - 1];
            for (let i in types) {
                switch (i) {
                    case 'select':
                    case 'multiSelect':
                        let cells = Object.keys(types[i] || {});
                        if (cells.includes(rowCell) || cells.includes(col) || cells.includes(rowCell + col)) {
                            type = i;
                        }
                        break;
                    default:
                        if (types[i]?.includes(rowCell) || types[i]?.includes(col) || types[i]?.includes(rowCell +
                            col)) {
                            type = i;
                        }
                }
            }
            return type;
        },
        /**
         * 检查统计
         * @param config
         * @param col
         * @param row
         * @param value
         */
        checkStatistic({
            config,
            col,
            row,
            value
        }) {
            if (!config) {
                config = this.getConfig('statistic');
            }
            if (config.enable) {
                let colEnable = true;
                let rowEnable = true;
                if (config.cols != '*' && config.cols.indexOf(col) < 0) { // 行统计
                    colEnable = false;
                }
                if (config.rows != '*' && !config.rows.includes(this.cells[row - 1])) { // 列统计
                    rowEnable = false;
                }
                value = Number(value);
                value = isNaN(value) ? 0 : value;
                let values = config.values;
                switch (config.type) {
                    case 'both':
                        if (colEnable) {
                            if (values.col[col]) {
                                values.col[col] += value;
                            } else {
                                values.col[col] = value;
                            }
                        }
                        if (rowEnable) {
                            if (values.row[row]) {
                                values.row[row] += value;
                            } else {
                                values.row[row] = value;
                            }
                        }
                        break;
                    case 'col':
                        if (colEnable) {
                            if (values.col[col]) {
                                values.col[col] += value;
                            } else {
                                values.col[col] = value;
                            }
                        }
                        break;
                    case 'row':
                    default:
                        if (rowEnable) {
                            if (values.row[row]) {
                                values.row[row] += value;
                            } else {
                                values.row[row] = value;
                            }
                        }
                }
            }
            return this;
        },

        /**
         * 获取配置信息
         * @param key
         * @param defVal
         * @returns {*|null}
         */
        getConfig(key, defVal = null) {
            let keys = key.split('.'),
                config = this.config;
            try {
                keys.forEach((i) => {
                    config = config[i]
                    if (config === undefined) {
                        throw new Error('not found ' + key);
                    }
                });
            } catch (e) {
                return defVal;
            }
            return config;
        },
        /**
         * 生成excel表头
         * @returns {ExcelSheet}
         */
        makeHead() {
            this.$rows[0] = [];
            this.$cols[0] = [];
            // 创建表头
            this.$head = document.createElement('tr');
            let width = this.getConfig('grid.width') || '';
            this.setAttributes(this.$head, {
                'class': ['sheet-col'],
                'data-col': 0,
            })
            this.$sheet.append(this.$head);
            if (!this.config.disableSerial) {
                // 生成序号元素
                this.$serialTd = this.makeSerial(this.$head, 'sheet-row sheet-head', '序号', 0);
                this.setAttributes(this.$serialTd, {
                    'data-col': 0,
                    'data-row': 0,
                    // width: width,
                });
                this.$rows[0][0] = this.$cols[0][0] = this.$serialTd;
            }

            let rowsNumber = this.getConfig('rows');
            let statistic = this.getConfig('statistic'); // 统计
            if (statistic.enable && (statistic.type == 'both' || statistic.type == 'col')) {
                rowsNumber += 1;
            }
            // 创建列
            for (var i = 0; i < rowsNumber; i++) {
                let tdEle = document.createElement('td');
                this.cells[i] = this.getCellValue(i);
                tdEle.innerHTML = this.cells[i];
                this.setAttributes(tdEle, {
                    'class': ['sheet-row', 'sheet-head'],
                    'width': width,
                    'data-col': 0,
                    'data-row': i + 1
                });
                this.$head.append(tdEle);
                this.$rows[i + 1] = [];
                this.$rows[i + 1][0] = this.$cols[0][i + 1] = tdEle;
            }

            return this;
        },
        getCellValue(i) {
            let index = i % 26,
                n = Math.floor(i / 26),
                value = this.rowCell[index];
            if (n >= 26) {
                value = this.getCellValue(n) + value;
            } else if (n >= 1) {
                value = this.rowCell[n - 1] + value;
            }
            return value;
        },
        /**
         * 表格尾部
         * @returns {Window.WenRunsExcel}
         */
        makeFooter() {
            this.$footer = document.createElement('div');
            this.setAttributes(this.$footer, {
                'class': ['sheet-footer'],
            });
            let addBtn = document.createElement('i');
            this.setAttributes(addBtn, {
                'class': ['fa', 'fa-plus'],
            })
            addBtn.addEventListener('click', () => {
                this.addCol(this.config.cols + 1, this.config.rows);
            })
            this.$footer.append(addBtn);
            this.$box.append(this.$footer);
            return this;
        },
        /**
         * 生成序号元素
         * @param className
         * @param value
         * @param col
         * @param row
         * @returns {HTMLTableDataCellElement}
         */
        makeSerial(pEl, className, value, col = 0, row = 0) {
            let serialTd = this.createSerialElement(className, value);
            pEl.append(serialTd);
            let tr = document.createElement('tr');
            this.setAttributes(tr, {
                'class': ['sheet-col'],
                'data-col': col,
            });
            let td = this.createSerialElement(className, value);
            this.setAttributes(td, {
                'data-col': col,
                'data-row': row,
            })
            tr.append(td);
            this.$serial.append(tr);
            return serialTd;
        },
        /**
         * 创建序号元素
         * @param className
         * @param value
         * @returns {HTMLTableDataCellElement}
         */
        createSerialElement(className, value) {
            let td = document.createElement('td');
            this.setAttributes(td, {
                'class': [className, 'sheet-serial'],
            });
            if (value) td.innerHTML = `<div class="serial-value">${value}</div>`
            return td;
        },
        /**
         * 设置元素属性
         * @param ele
         * @param attributes
         * @returns {ExcelSheet}
         */
        setAttributes(ele, attributes) {
            if (attributes && ele) {
                if (typeof attributes == 'object') {
                    for (var name in attributes) {
                        let value = attributes[name];
                        if (value instanceof Array) {
                            value = value.join(' ');
                        } else if (typeof value == 'object') {
                            if (name == 'style') {
                                let style = '';
                                for (var styleName in value) {
                                    style += styleName + ':' + value[styleName] + ';'
                                }
                                value = style;
                            } else {
                                value = JSON.stringify(value);
                            }
                        }
                        ele.setAttribute(name, value)
                    }
                } else {
                    ele.setAttribute(attributes, '');
                }
            }
            return this;
        },
        /**
         * css样式挂载
         * @returns {ExcelSheet}
         */
        style() {
            if (document.querySelector('style[wen-sheet]')) {
                return this;
            }
            this.$style = document.createElement('style');
            this.setAttributes(this.$style, 'wen-sheet');
            document.querySelector('head').append(this.$style);
            let width = this.getConfig('grid.width', ''),
                height = this.getConfig('grid.height', ''),
                tableWidth = '100%';
            if (width) {
                if (typeof width == 'number') {
                    width = width + 'px';
                }
                tableWidth = '';
            } else {
                width = '100%';
            }
            if (height) {
                if (typeof height == 'number') {
                    height = height + 'px';
                }
            } else {
                height = '30px';
            }
            this.$style.innerHTML = `
                            .wen-excel-sheet {
                                position: relative;
                                // font-size: .7rem;
                                user-select: text;
                                -webkit-user-select: text;
                                overflow: hidden;
                                padding: 0px;
                            }
                            .wen-excel-sheet * {
                                user-select: text;
                                -webkit-user-select: text;
                            }
                            .wen-excel-sheet .wen-sheet {
                                width: 100%;
                                padding: 0px;
                                margin: 0px;
                                overflow: auto;
                                height: 100%;
                            }
                            .wen-excel-sheet .sheet-table {
                                width: ${tableWidth};
                                height: 100%;
                                border-spacing: 2px;
                                margin: 0px;
                                padding: 0px;
                                border-collapse: collapse;
                                border-top: 1px solid ${this.getConfig('grid.borderColor')};
                                border-left: 1px solid ${this.getConfig('grid.borderColor')};
                            }
                            .wen-excel-sheet .sheet-serial-table {
                                position: absolute;
                                top: 0px;
                                left: 0px;
                                z-index: 999;
                                width: auto;
                                height: 100%;
                                border-left: 1px solid ${this.getConfig('grid.borderColor')};
                            }
                            .wen-excel-sheet .sheet-col {

                            }

                            .wen-excel-sheet .sheet-value,
                            .wen-excel-sheet .sheet-input,
                            .wen-excel-sheet .sheet-select{
                                -webkit-box-sizing: border-box;
                                -moz-box-sizing: border-box;
                                box-sizing: border-box;
                                padding: 0px 5px;
                                width: ${width};
                                overflow:hidden;
                                text-overflow: ellipsis;
                                display: block;
                                white-space: nowrap;
                                min-width: 0;
                            }
                            .wen-excel-sheet .sheet-input,
                            .wen-excel-sheet .sheet-select{
                                height: 100%;
                                vertical-align: middle;
                                text-align: left;
                                line-height: ${height};
                                border: 0px;
                                outline-width: inherit;
                            }
                            .wen-excel-sheet .sheet-input::-webkit-input-placeholder,
                            .wen-excel-sheet .sheet-select::-webkit-input-placeholder{
                                color: darkgray;
                            }
                            .wen-excel-sheet .sheet-input:-ms-input-placeholder,
                            .wen-excel-sheet .sheet-select:-ms-input-placeholder{
                                color: darkgray;
                            }
                            .wen-excel-sheet .sheet-input::placeholder,
                            .wen-excel-sheet .sheet-select::placeholder{
                                color: darkgray;
                            }
                            .wen-excel-sheet .sheet-select{
                                cursor:pointer;
                                width: calc(${width} - 10px);
                            }
                            .wen-excel-sheet .sheet-select:empty::before{
                                content: attr(placeholder);
                                color: #aaa;
                                line-height: ${height};
                            }
                            .wen-excel-sheet .sheet-select::after{
                                content: ' ';
                                display:inline-block;
                                width: 0px;
                                height: 0px;
                                border-top: 5px solid gray;
                                border-left: 5px solid transparent;
                                border-right: 5px solid transparent;
                                border-bottom: 0px;
                                position:absolute;
                                right:  2px;
                                top: calc(50% - 2px);
                                will-change: transform;
                                transition: transform 100ms linear;
                                border-top-left-radius: 3px;
                                border-top-right-radius: 3px;
                            }

                            .wen-excel-sheet .sheet-select[select]::after{
                                transform: rotate(180deg);
                            }

                            .wen-excel-sheet .sheet-row {
                                margin: 0px;
                                border-right: 1px solid ${this.getConfig('grid.borderColor')};
                                border-bottom: 1px solid ${this.getConfig('grid.borderColor')};
                                position:relative;
                                color: #666;
                                white-space: nowrap;
                                height: ${height};
                            }
                            .wen-excel-sheet .sheet-row *{
                                -webkit-user-select: text,
                                user-select: text,
                            }

                            .wen-excel-sheet .sheet-row.select{
                                position: relative;
                            }

                            .wen-excel-sheet .sheet-row:empty:before{
                                content:attr(placeholder);
                                color: #ccc;
                            }

                            .wen-excel-sheet .sheet-col {
                                position: relative;
                            }
                            .wen-excel-sheet .sheet-head {
                                height: 0px;
                                text-align: center;
                                box-shadow: 0px 0px 15px ${this.getConfig('grid.borderColor')};
                                background: #eeeeee;
                                line-height: unset;
                            }

                            .wen-excel-sheet .sheet-serial {
                                color: red;
                                text-align: center;
                                background: #fde2e2;
                                padding: 0px;
                                margin: 0px;
                                height: 30px;
                                border-right:0px;
                            }
                            .wen-excel-sheet .sheet-table .sheet-serial .serial-value{
                                padding: 0px 5px;
                            }
                            .wen-excel-sheet .sheet-serial-table .sheet-serial{
                                background: #fde2e2;
                                border-right: 1px solid ${this.getConfig('grid.borderColor')} !important;
                            }
                            .wen-excel-sheet .sheet-serial-table .sheet-head{
                                background: #fde2e2;
                            }

                            .wen-excel-sheet .wen-select{
                                position: fixed;
                                background: white;
                                z-index: 9999;
                                box-shadow: 1px 1px 4px 0px  darkgray;
                                padding:0px;
                                border-bottom-left-radius: 3px;
                                border-bottom-right-radius: 3px;
                                overflow:hidden;
                            }
                            .wen-excel-sheet .wen-select li{
                                list-style: none;
                            }
                            .wen-excel-sheet .wen-select li .options-ul{
                                padding:0px;
                                margin:0px;
                                width: 100%;
                                overflow-y: auto;
                                overflow-x: hidden;
                                max-height: 400px;
                            }
                            .wen-excel-sheet .wen-select li .options-ul li{
                                padding: 5px;
                                overflow: hidden;
                                text-overflow: ellipsis;
                                white-space: normal;
                                word-break: break-all;
                            }

                            .wen-excel-sheet .wen-select .options-ul li.option-li:hover,
                            .wen-excel-sheet .wen-select .options-ul li[selected]{
                                color:white;
                                cursor:pointer;
                                background: rgba(255,99,71,.7);
                            }
                            .wen-excel-sheet .wen-select .options-ul li[selected]{
                                background: rgba(255,99,71, 1);
                            }
                            .wen-excel-sheet .wen-select li.wen-select-search{
                                padding:0px;
                                position:relative;
                            }
                            .wen-excel-sheet .wen-select li.wen-select-search button{
                                position:absolute;
                                width: 40px;
                                top:0px;
                                right:0px;
                                height: 100%;
                                border:0px;
                            }
                            .wen-excel-sheet .wen-select li.wen-select-search input{
                                outline: none;
                                border: 0px;
                                text-align: center;
                                background: white;
                                color: black;
                                width: 100%;
                                padding: 5px;
                                padding-right: 45px;
                                box-sizing: border-box;
                                -webkit-box-sizing: border-box;
                                -ms-box-sizing: border-box;
                                -moz-box-sizing: border-box;
                                border-bottom: 1px solid #f4f4f4;
                            }

                            .wen-excel-sheet .sheet-footer{
                                text-align:center;
                                position:relative;
                            }
                            .wen-excel-sheet .sheet-footer i.fa-plus{
                                border: 1px solid #f4f4f4;
                                color: lightslategray;
                                padding: 5px 15px;
                                cursor:pointer;
                                border-radius: 5px;
                                --webkit-border-radius: 5px;
                                --moz-border-radius: 5px;
                                --ms-border-radius: 5px;
                                --o-border-radius: 5px;
                            }
                            .wen-excel-context-menu{
                                background: lightgray;
                                position: absolute;
                                width: 200px;
                                box-shadow: 0px 0px 10px 0px lightgray;
                                z-index: 999999999;
                                padding: 10px 0px;
                                box-sizing: border-box;
                                -moz-box-sizing: border-box;
                                -webkit-box-sizing: border-box;
                                -ms-box-sizing: border-box;
                                -o-box-sizing: border-box;
                                border-radius: 5px;
                                -webkit-border-radius: 5px;
                                -moz-border-radius: 5px;
                                -ms-border-radius: 5px;
                                -o-border-radius: 5px;
                            }
                            .wen-excel-context-menu>div{
                                cursor:pointer;
                                padding: 3px 20px;
                            }
                            .wen-excel-context-menu>div:hover{
                                background: whitesmoke;
                            }

                            .wen-excel-context-menu>div[disabled]{
                                color: darkgray;
                                background: lightgray;
                            }

                            .wen-context-target{
                                position:relative;
                            }
                            .wen-context-target:before{
                                content: '';
                                display: block;
                                width: calc(100% + 2px);
                                height: calc(100% + 2px);
                                position: absolute;
                                border: 1px solid red;
                                top: -1px;
                                left: -1px;
                            }
                            `;
            return this;
        }
    }
}
